/*
 * Copyright (C) 2022 KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */

#include "desktopfilemanager.h"
#include <QStandardPaths>
#include <QDir>
#include <QUrl>
#include <QApplication>
#include <QThread>
#include <QDebug>
#include <KDesktopFile>
#include <KConfigGroup>
#include <KDirLister>

Q_GLOBAL_STATIC_WITH_ARGS(QStringList, blackListApps, ({
    "software-properties-livepatch.desktop", "mate-color-select.desktop",
    "blueman-adapters.desktop", "mate-user-guide.desktop",
    "nm-connection-editor.desktop", "debian-uxterm.desktop",
    "debian-xterm.desktop", "im-config.desktop", "fcitx.desktop",
    "fcitx-configtool.desktop", "onboard-settings.desktop",
    "info.desktop", "ukui-power-preferences.desktop",
    "ukui-power-statistics.desktop", "software-properties-drivers.desktop",
    "software-properties-gtk.desktop", "gnome-session-properties.desktop",
    "org.gnome.font-viewer.desktop", "xdiagnose.desktop",
    "gnome-language-selector.desktop", "mate-notification-properties.desktop",
    "transmission-gtk.desktop", "mpv.desktop",
    "system-config-printer.desktop", "org.gnome.DejaDup.desktop",
    "yelp.desktop", "mate-about.desktop", "time.desktop",
    "network.desktop", "shares.desktop", "mate-power-statistics.desktop",
    "display-im6.desktop", "display-im6.q16.desktop",
    "openjdk-8-policytool.desktop", "kylin-io-monitor.desktop",
    "wps-office-uninstall.desktop", "wps-office-misc.desktop"
}))

DesktopFileManager::DesktopFileManager(QObject *parent)
    : QObject{parent}
{
    loadLocalDesktopFiles();
}

const QStringList DesktopFileManager::localDesktopFiles() const
{
    return m_localDekstopFiles;
}

void DesktopFileManager::loadLocalDesktopFiles()
{
    QStringList appLocations = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation);
    QDir appsDir;
    for (auto &location : qAsConst(appLocations)) {
        appsDir.setPath(location);
        if (!appsDir.exists()) {
            continue;
        }
        watchDesktopfilePath(QUrl::fromUserInput(location));
        auto fileInfoList = appsDir.entryInfoList(QStringList() << "*.desktop");
        for (auto &fileInfo : qAsConst(fileInfoList)) {
            if (appIconCanDisplay(fileInfo.absoluteFilePath())) {
                m_localDekstopFiles.append(fileInfo.absoluteFilePath());
            }
        }
    }

    std::sort(m_localDekstopFiles.begin(), m_localDekstopFiles.end(),
              [] (const QString &desktop1, const QString &desktop2) {
        QStringList tmpList1 = desktop1.split("/");
        QStringList tmpList2 = desktop2.split("/");
        QString desktopName1 = tmpList1.isEmpty() ? desktop1 : tmpList1.constLast();
        QString desktopName2 = tmpList2.isEmpty() ? desktop2 : tmpList2.constLast();
        return desktopName1.toLower() < desktopName2.toLower();
    });
}

bool DesktopFileManager::appIconCanDisplay(const QString &desktopFile) const
{
    KDesktopFile kDesktopFile(desktopFile);
    KConfigGroup desktopGroup = kDesktopFile.desktopGroup();
    QString desktopName = kDesktopFile.fileName().split('/').last();
    if (desktopGroup.readEntry("NoDisplay").contains("true") ||
//            kDesktopFile.readIcon().isEmpty() ||
            !kDesktopFile.hasApplicationType() ||
            blackListApps->contains(desktopName) ||
            desktopGroup.readEntry("NotShowIn").contains("UKUI") ||
            (!desktopGroup.readEntry("OnlyShowIn").isEmpty()
            && !desktopGroup.readEntry("OnlyShowIn").contains("UKUI"))) {
        return false;
    }
    return true;
}

void DesktopFileManager::watchDesktopfilePath(const QUrl &url)
{
    KDirLister *appListener = new KDirLister(this);
    appListener->setNameFilter("*.desktop");
    appListener->setAutoUpdate(true);
    appListener->openUrl(url, KDirLister::OpenUrlFlag::Keep);

    while (!appListener->isFinished()) {
        qApp->processEvents(QEventLoop::EventLoopExec);
        QThread::msleep(1);
    }

    connect(appListener, &KCoreDirLister::itemsAdded, this, &DesktopFileManager::onDesktopfilesAdded);
    connect(appListener, &KCoreDirLister::itemsDeleted, this, &DesktopFileManager::onDesktopfilesDeleted);

}

void DesktopFileManager::onDesktopfilesAdded(const QUrl &directoryUrl, const KFileItemList &desktopFiles)
{
    Q_UNUSED(directoryUrl);
    for (auto &desktopFile : qAsConst(desktopFiles)) {
        const QString desktopFilePath = desktopFile.url().path();
        if (!appIconCanDisplay(desktopFilePath)) {
            continue;
        }
        m_localDekstopFiles.append(desktopFilePath);
        Q_EMIT desktopFileAdded(desktopFilePath);
    }
}

void DesktopFileManager::onDesktopfilesDeleted(const KFileItemList &desktopFiles)
{
    for (auto &desktopFile : qAsConst(desktopFiles)) {
        const QString desktopFilePath = desktopFile.url().path();
        if (m_localDekstopFiles.contains(desktopFilePath)) {
            m_localDekstopFiles.removeOne(desktopFilePath);
            Q_EMIT desktopFileDeleted(desktopFilePath);
        }
    }
}
